package top.lixunda.commerce.common.core.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import top.lixunda.commerce.common.core.controller.wrapper.BaseDataQuerySqlWrapper;
import top.lixunda.commerce.common.core.controller.wrapper.PageConvertWrapper;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;

/**
 * @author Xumda
 * @version time:2019/12/19 15:39
 */
@SuppressWarnings({"WeakerAccess", "unused"})
public abstract class BaseConvertEntityController<M extends ServiceImpl<N, T>, N extends BaseMapper<T>, T,
        S extends ServiceImpl<P, E>, P extends BaseMapper<E>, E, D> extends BaseEntityController<M, N, T>
        implements IConvertEntityController<E, T, D> {

    @SuppressWarnings("SpringJavaAutowiredMembersInspection")
    @Autowired
    private S s;

    /**
     * 转换方法
     */
    private final Function<List<T>, List<D>> convertFunction;

    private final SFunction<E, ?> entityIdFun;

    private final SFunction<T, ?> detailIdFun;

    protected BaseConvertEntityController(Function<List<T>, List<D>> convertFunction, SFunction<E, ?> entityIdFun,
                                          SFunction<T, ?> detailIdFun) {
        this.convertFunction = convertFunction;
        this.entityIdFun = entityIdFun;
        this.detailIdFun = detailIdFun;
    }

    /**
     * 基础表的service类
     *
     * @return 基础表的service对象
     */
    public ServiceImpl<P, E> getAtomicService() {
        return s;
    }

    /**
     * 级联分页
     *
     * @return 级联数据列表
     */
    private Page<D> convertPage(Page<D> page, QueryWrapper<E> wrapper, QueryWrapper<T> queryWrapper,
                                SFunction<E, ?> idFunction, SFunction<T, ?> detailIdFunction,
                                Function<List<T>, List<D>> convertFun) {
        Page<E> tempPage = new Page<E>().setCurrent(page.getCurrent()).setSize(page.getSize());
        tempPage.setOrders(page.getOrders());
        IPage<E> goodOrderPage = getAtomicService().page(tempPage, wrapper == null ?
                new QueryWrapper<E>().lambda().select(idFunction) : wrapper.lambda().select(idFunction));
        page.setSize(goodOrderPage.getSize()).setTotal(goodOrderPage.getTotal()).setPages(goodOrderPage.getPages())
                .setCurrent(goodOrderPage.getCurrent());
        List<E> entityList = goodOrderPage.getRecords();
        if (entityList.size() == 0) {
            return page.setRecords(Collections.emptyList());
        }
        List<String> idList = new ArrayList<>(entityList.size());
        for (E e : entityList) {
            idList.add(String.valueOf(idFunction.apply(e)));
        }
        List<T> dtoList = getBaseMapper().selectList(queryWrapper == null ?
                new QueryWrapper<T>().lambda().in(detailIdFunction, idList) :
                queryWrapper.lambda().in(detailIdFunction, idList));
        page.setRecords(convertFun.apply(dtoList));
        return page;
    }

    @Override
    public D getConvertById(String id) {
        List<T> list = getBaseService().list(new QueryWrapper<T>().lambda().eq(detailIdFun, id));
        if (list == null || list.size() == 0) {
            return null;
        }
        List<D> resultList = convertFunction.apply(list);
        return resultList.size() > 0 ? resultList.get(0) : null;
    }

    @Override
    public List<D> listConvertByIds(List<String> idList) {
        List<T> list = getBaseService().list(new QueryWrapper<T>().lambda().in(detailIdFun, idList));
        if (list == null || list.size() == 0) {
            return Collections.emptyList();
        }
        return convertFunction.apply(list);
    }

    @Override
    public D getOneConvert(BaseDataQuerySqlWrapper<T> queryWrapper) {
        List<T> list = getBaseService().list(queryWrapper.toQueryWrapper());
        if (list == null || list.size() == 0) {
            return null;
        }
        List<D> resultList = convertFunction.apply(list);
        return resultList.size() > 0 ? resultList.get(0) : null;
    }

    @Override
    public List<D> listConvert(BaseDataQuerySqlWrapper<T> queryWrapper) {
        List<T> list = getBaseService().list(queryWrapper.toQueryWrapper());
        if (list == null || list.size() == 0) {
            return Collections.emptyList();
        }
        return convertFunction.apply(list);
    }

    @Override
    public List<D> listConvert() {
        return convertFunction.apply(getBaseService().list());
    }

    @Override
    public int countConvert(BaseDataQuerySqlWrapper<E> queryWrapper) {
        return getAtomicService().count(queryWrapper.toQueryWrapper());
    }

    @Override
    public int countConvert() {
        return getAtomicService().count();
    }

    @Override
    public Page<D> pageConvert(PageConvertWrapper<E, T, D> pageWrapper) {
        return convertPage(pageWrapper.getPage(), pageWrapper.getPageWrapper().toQueryWrapper(),
                pageWrapper.getQueryWrapper().toQueryWrapper(), entityIdFun, detailIdFun, convertFunction);
    }

    @Override
    public Page<D> pageConvert(Page<D> page) {
        return convertPage(page, null, null, entityIdFun, detailIdFun, convertFunction);
    }
}
